package io.bio;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class ChannelDemo {
    public static void main(String[] args) {
        //fileChannelDemo();
        socketChannelDemo();
    }

    public static void socketChannelDemo(){
        try {
            // 创建socketChannel
            SocketChannel socketChannel = SocketChannel.open();
            // 配置为非阻塞
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("127.0.0.1",80));
            // 或许连接还没有建立，socketChannel.connect 方法就返回了，
            // 因此我们不断的自旋，检查当前是否是连接到了主机。
            while(!socketChannel.finishConnect()){

            }
            // 读取数据
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 如果read 返回-1 表示连接以及被中断了
            int readLength = socketChannel.read(byteBuffer);

            // 写入数据
            String data = "新数据";
            // 切换到写模式
            byteBuffer.clear();
            byteBuffer.put(data.getBytes());
            // 切换到读模式
            byteBuffer.flip();
            while(byteBuffer.hasRemaining()){
                socketChannel.write(byteBuffer);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * FileChannel 示例代码
     */
    public static void fileChannelDemo(){
        //Java.nio.charset.Charset处理了字符转换问题。它通过构造CharsetEncoder和CharsetDecoder将字符序列转换成字节和逆转换。
        Charset chartset = Charset.forName("GBK");
        CharsetDecoder decoder = chartset.newDecoder();
        CharsetEncoder encoder = chartset.newEncoder();
        try {
            // 打开 FileChannel通道, rw 为读写模式
            RandomAccessFile file = new RandomAccessFile("G://test.txt","rw");
            FileChannel channel = file.getChannel();
            // 读取数据
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            int length = channel.read(byteBuffer);
            System.out.println(new String(byteBuffer.array(),0,length,Charset.forName("GBK")));

            // 写入数据
            String data = "这是一个测试文件";
            CharBuffer charBuffer = CharBuffer.allocate(1024);
            charBuffer.put(data);
            // 移动RandomAccessFile 的指针到最后，实现追加
            file.seek(file.length());
            while (charBuffer.hasRemaining()){
                charBuffer.flip();
                ByteBuffer buffer = encoder.encode(charBuffer);
                channel.write(buffer);
            }
            // 强制刷新磁盘  FileChannel的force()方法将所有未写入的数据从通道刷新到磁盘中。
            // 在你调用该force()方法之前，出于性能原因，操作系统可能会将数据缓存在内存中，
            // 因此您不能保证写入通道的数据实际上写入磁盘。
            channel.force(true);
            // 关闭
            channel.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
